package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"time"

	"github.com/bndr/gojenkins"
	badger "github.com/dgraph-io/badger/v4"
	"github.com/gen2brain/beeep"
	"github.com/labstack/gommon/log"
	"github.com/mitchellh/go-homedir"
	"github.com/wailsapp/wails/v2/pkg/runtime"
)

const (
	LogEvent    = "logEvent"
	LogEndEvent = "logEndEvent"
)

// App struct
type App struct {
	ctx context.Context
	db  *badger.DB

	// cache
	jenkinsClient  *gojenkins.Jenkins
	jenkinsQueueID int64
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called at application startup
func (a *App) startup(ctx context.Context) {
	// Perform your setup here
	a.ctx = ctx

	homeDir, err := homedir.Dir()

	if err != nil {
		panic(err)
	}
	a.db, err = badger.Open(badger.DefaultOptions(homeDir + "/.config/penetration/data.db"))
	if err != nil {
		panic(err)
	}
}

// domReady is called after the front-end dom has been loaded
func (a App) domReady(ctx context.Context) {
	// Add your action here
}

// shutdown is called at application termination
func (a *App) shutdown(ctx context.Context) {
	// Perform your teardown here
	a.db.Close()
}

func (a *App) ExecJob(jenkinsInfo JenkinsInfo) error {

	info, err := json.Marshal(jenkinsInfo)
	if err != nil {
		return err
	}

	txn := a.db.NewTransaction(true)
	err = txn.Set([]byte("jenkins_info"), info)
	if err != nil {
		return err
	}
	err = txn.Commit()
	if err != nil {
		return err
	}

	ctx := context.Background()
	// jenkins := gojenkins.CreateJenkins(nil, "http://61.177.141.230:48080/", "2390", "11eb29981c92508dad2f5d56716b588225")
	jenkins := gojenkins.CreateJenkins(nil, jenkinsInfo.Url, jenkinsInfo.Username, jenkinsInfo.Token)
	jenkins, err = jenkins.Init(ctx)
	if err != nil {
		return err
	}
	a.jenkinsClient = jenkins

	queueId, err := jenkins.BuildJob(ctx, "DevOps-OpsWebApi", nil)
	if err != nil {
		return err
	}
	a.jenkinsQueueID = queueId

	// s, err := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
	// 	Title:   "提示",
	// 	Message: "运行中",
	// 	Buttons: []string{},
	// })
	// if err != nil {
	// 	return err
	// }
	// fmt.Println(s)

	go a.jobBuildLog()
	return nil
}

func (a *App) jobBuildLog() {

	ctx := context.Background()
	job, err := a.jenkinsClient.GetBuildFromQueueID(ctx, a.jenkinsQueueID)
	if err != nil {
		log.Error(err)
		return
	}

	index := int64(0)

	hasmore := true
	for hasmore {
		resp, err := job.GetConsoleOutputFromIndex(ctx, index)
		if err != nil {
			fmt.Println(err)
			return
		}
		hasmore = resp.HasMoreText

		runtime.EventsEmit(a.ctx, LogEvent, resp.Content)
		index = resp.Offset
		time.Sleep(1 * time.Second)
	}

	// 发送结束信息
	runtime.EventsEmit(a.ctx, LogEndEvent, "end")
	a.jenkinsQueueID = -1
	err = beeep.Beep(beeep.DefaultFreq, beeep.DefaultDuration)
	if err != nil {
		panic(err)
	}
	err = beeep.Notify("Title", "Message body", "assets/information.png")
	if err != nil {
		panic(err)
	}
}

func (a *App) StopJob() error {
	ctx := context.Background()
	job, err := a.jenkinsClient.GetBuildFromQueueID(ctx, a.jenkinsQueueID)
	if err != nil {
		return err
	}
	_, err = job.Stop(ctx)
	if err != nil {
		return err
	}

	return nil
}

type JenkinsInfo struct {
	Url      string
	Username string
	Token    string
}

func (a *App) GetJenkinsInfo() JenkinsInfo {
	// return JenkinsInfo{
	// 	Url:      "http://localhost:8080/",
	// 	Username: "admin",
	// 	Token:    "119239e64b076b7fb57508ed88a037caf5",
	// }

	jenkinsInfo := JenkinsInfo{}

	err := a.db.View(func(txn *badger.Txn) error {
		it, err := txn.Get([]byte("jenkins_info"))
		if err != nil {
			return err
		}
		return it.Value(func(val []byte) error {
			return json.Unmarshal(val, &jenkinsInfo)
		})
	})

	// info, err := a.db.Get([]byte("jenkins_info"))
	if err != nil {
		fmt.Println(err)
		return jenkinsInfo
	}

	return jenkinsInfo
}

type PortForwardInfo struct {
	Listener string
	Forward  string
	Protocol string
}

func (a *App) AddPortForward(info PortForwardInfo) {

}

func (a *App) PortForward(info PortForwardInfo) error {
	ctx := context.Background()

	go func() {
		err := PortForward(ctx, info)
		_ = err
	}()

	return nil
}

func PortForward(ctx context.Context, info PortForwardInfo) error {

	lister, err := net.Listen(info.Protocol, info.Listener)
	if err != nil {
		return err
	}
	defer lister.Close()

	for {
		select {
		case <-ctx.Done():
			return nil
		default:
			incoming, err := lister.Accept()
			if err != nil {
				return err
			}
			go handleClient(incoming, info)
		}
	}
}

func handleClient(clientConn net.Conn, info PortForwardInfo) {
	defer clientConn.Close()

	forward, err := net.Dial(info.Protocol, info.Forward)
	if err != nil {
		log.Fatal(err)
	}
	defer forward.Close()

	// 开始转发数据
	go func() {
		_, err := io.Copy(forward, clientConn)
		if err != nil {
			log.Fatal(err)
		}
	}()

	_, err = io.Copy(clientConn, forward)
	if err != nil {
		log.Fatal(err)
	}
}
